#include <logbase.h>
#include <genrand.h>
#include <pthread.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <queBase.h>
#include <errno.h>
#include <sys/mman.h>

#include <stdio.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <sys/wait.h>

/*
‌共享内存（shm）‌：
‌优点‌：读写速度快，因为数据存储在物理内存中。
‌缺点‌：存储量有限，通常不能超过物理内存的大小‌
‌内存映射（mmap）‌：
‌优点‌：可以处理大文件，存储量不受物理内存限制，因为数据存储在磁盘上‌
‌缺点‌：读写速度较慢，因为数据需要从磁盘读取到内存中‌
在64KB共享内存大小下，mmap和shm性能相近，但在1GB共享内存大小时，shm表现最佳，mmap慢约10%‌
*/

struct mmapOptStruct
{
    int fd;
    char *ptr;
};

int mmapOpen(struct mmapOptStruct *mopt)
{
    if (!mopt)
    {
        logdebugc("");
        return -1;
    }
    mopt->fd = -1;
    mopt->ptr = NULL;

    mopt->fd = open("/tmp/tmpMmap.txt", O_RDWR | O_CREAT | O_TRUNC, 0666);
    if (-1 == mopt->fd)
    {
        perror("open mmap file err");
        return -1;
    }
    // 配置文件大小， 必须。
    ftruncate(mopt->fd, 1024);
    mopt->ptr = mmap(NULL, 1024, PROT_READ | PROT_WRITE, MAP_SHARED, mopt->fd, 0);
    if (mopt->ptr == MAP_FAILED)
    {
        perror("mmap get ptr err");
        close(mopt->fd);
        mopt->fd = -1;
        mopt->ptr = NULL;
        return -1;
    }
    return 0;
}

int mmapClose(struct mmapOptStruct *mopt)
{
    if (!mopt)
    {
        logdebugc("");
        return -1;
    }
    if (!(mopt->fd > 0 && mopt->ptr))
    {
        logerrorc("");
        return -1;
    }
    munmap(mopt->ptr, 1024);
    close(mopt->fd);
    return 0;
}

int main(int argc, const char *argv[])
{
    pid_t pid = fork();
    struct mmapOptStruct tmpmm = {-1, NULL};
    mmapOpen(&tmpmm);
    logdebugc("%d,%p", tmpmm.fd, tmpmm.ptr);
    if (pid == -1)
    {
        // 错误处理
        perror("fork failed");
        return 1;
    }
    else if (pid == 0)
    {
        logdebugc("child's pid:%d", getpid());
        usleep(500 * 1000);
        logdebugc("%s", tmpmm.ptr);
        sleep(1);
        logdebugc("%s", tmpmm.ptr);
        mmapClose(&tmpmm);
    }
    else
    {
        int tmpflag;
        logdebugc("prarent's pid:%d", getpid());
        if(tmpmm.ptr == NULL)
        {
            goto quitmmap;
        }
        snprintf(tmpmm.ptr, 100, "12345");
        logdebugc("prarent input 1");
        sleep(1);
        logdebugc("prarent input 2");
        snprintf(tmpmm.ptr, 100, "abc");
        sleep(1);
        mmapClose(&tmpmm);
quitmmap:
        // tmpflag == 子进程pid
        tmpflag = waitpid(pid, NULL, 0);
        logdebugc("prarent finish:%d", tmpflag);
    }
    return 0;
}